﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using HAP = HtmlAgilityPack;
using TaobaoPick.util;
using TaobaoPick.storage;
using System.Windows.Forms;
using TaobaoPick.taboao;
using System.Xml;
namespace TaobaoPick
{
    public class TaobaoSearchExplorer
    {

        public TaobaoSearchExploreContext createTask(String taskName, String rootCat, String q)
        {



            return null;
        }
        TaobaoSearchExploreContext m_exploreContext = null;

        public void createExploreContext(String url,String content)
        {
        }
        public List<Hashtable> listTasks()
        {
            return null;
        }
        public void LoadContext(Guid taskId)
        {

        }

        public class TaoResult
        {
            public HTMLHelpers.UrlComposite   urlComposite;
            public List<Hashtable> cats=null;
            public bool hasCats = false;
            public int itemCount = 0;
            public XmlDocument pageDoc = null;
            public bool hasSales = false;
            public bool hasProcessError = false;
            public List<String> errorMsgs = new List<string>();
        }

        public TaoResult processPage(String url,String content)
        {
            TaoResult result=new TaoResult();
            result.urlComposite=HTMLHelpers.parseURL(url);
            HAP.HtmlDocument doc = new HAP.HtmlDocument();
            doc.LoadHtml(content);
            try
            {
                result.cats = parseCATs(url, doc);
                result.hasCats = (result.cats.Count > 0);
            }
            catch (Exception e)
            {
                result.errorMsgs.Add(e.Message);
                ErrorLogs.logErrorURL(url, e.Message);
            }

            try
            {
                TaobaoQueryParser parser = new TaobaoQueryParser();
                XmlDocument xmldoc=null;
                xmldoc = parser.processHTMLDocument(doc);
                XmlNodeList list = xmldoc.GetElementsByTagName("list-item");
                result.itemCount = list.Count;
                result.hasSales = TaoLogPageHelper.hasValidSale(xmldoc);
                result.pageDoc = xmldoc;
            }
            catch (Exception e)
            {
                result.errorMsgs.Add(e.Message);
                result.hasProcessError = true;
                ErrorLogs.logErrorURL(url, e.Message);
            }
            return result;
        }

        public void SaveContext()
        {
            if(String.IsNullOrWhiteSpace(m_exploreContext.FileName))
            {
                MessageBox.Show("No file name, please use save as");
                return;
            }
            m_exploreContext.Save(m_exploreContext.FileName);
        }
        public void LoadContext(String fileName)
        {
            m_exploreContext = new TaobaoSearchExploreContext();
        }

        ///GOTO init Page
        
        /// <summary>
        ///  init process,
        /// </summary>
        /// <param name="mode">=0 no cat, =1 with cat,  no cat 代表一直往下找 </param>
        /// <param name="catfilters"></param>
        public void initProcess(int mode, HashSet<String> catfilters, int pagelimit,bool stopWhileNoSale)
        {
            
            


        }


        //有一個config...
        protected XmlDocument convertItemListXML(String url,HAP.HtmlDocument hapDoc,out Boolean hasItem)
        {
            TaobaoQueryParser parser = new TaobaoQueryParser();
            XmlDocument doc = null;
            try
            {
                doc = parser.processHTMLDocument(hapDoc);
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.Write(e.Message);
                ErrorLogs.logErrorURL(url, e.Message);
                throw e; //繼續往上丟,代表因為是失敗的..會轉移到log.
            }
            XmlNodeList list = doc.GetElementsByTagName("list-item");
            if (list.Count == 0)
            {
                hasItem = false;
            }
            else
                hasItem = true;
            return doc;
        }

        bool isLeafPage = false;
        int currentPageCount = 0;
        public bool processItemPage(String url, HAP.HtmlDocument hapDoc)
        {
            return false;
        }

        public bool doProcess(String url, HAP.HtmlDocument hapDoc)
        {
            switch (m_exploreContext.PickOP())
            {
                case TaobaoSearchExploreContext.PageOP.CAT:
                     List<Hashtable> subcats=parseCATs(url, hapDoc);
                     //POP 目前url
                     m_exploreContext.popPageOP();
                    Hashtable topPage=m_exploreContext.popURLConfig();
                    if (subcats.Count == 0)
                        isLeafPage = true;
                    else
                        isLeafPage = false;
                       foreach (Hashtable ht in subcats)
                         {
                             m_exploreContext.pushURLConfig(ht);
                             m_exploreContext.pushPageOP(TaobaoSearchExploreContext.PageOP.CAT);
                         }
                         m_exploreContext.pushURLConfig(topPage);
                         m_exploreContext.pushPageOP(TaobaoSearchExploreContext.PageOP.ITEM);
                         currentPageCount = 0;
                         return doProcess(url, hapDoc);
                case TaobaoSearchExploreContext.PageOP.ITEM:
                         if (checkIsList(url) == false)
                         {
                             MessageBox.Show("先進入列表模式");
                             return false;
                         }
                         if (currentModeNext())
                         {
                             
                             //if No Sale -->
                             //而且NoSale -->
                             //碰到false -->
                             //怎樣算Next ? -->POP -->Push ?
                             //不管如何都會把Next放上來
                             return processItemPage(url, hapDoc);
                         }
                         break;
                           //是否超過?
            }
            return true;
        }

        protected bool currentModeNext()
        {
            if (isLeafPage)
            {
                if (currentPageCount < 99)
                    return true;
                return false;
            }
            else
            {
                if (currentPageCount > 10)
                    return false;
                return true;
            }
        }
        protected bool checkIsList(String url)
        {
            Hashtable ht = HTMLHelpers.parseParameter(url);
            String style = (String)ht["style"];
            if ("list".Equals(style) == false)
                return false;
            return true;
        }


        public  List<Hashtable> parseCATs(String url, HAP.HtmlDocument doc)
        {
            List<Hashtable> result = new System.Collections.Generic.List<Hashtable>();
            int lpos = url.LastIndexOf("/");
            String urlprefix = url.Substring(0, lpos);

            //雖然有些限制,但是如果限制在url上有cat的裁處理 是比較安全的做法
            Hashtable paramht = HTMLHelpers.parseParameter(url);
            String urlCat = (String)paramht["cat"];
            String q = (String)paramht["q"];

            bool hasURLCat = (String.IsNullOrWhiteSpace(urlCat) == false);

            //isLeaf 不是很重要    

            //更新一下 cat的關係.
            List<Hashtable> crumbs = processCrumb(doc);


            String[] cates = { "//div[@class='cate-panel recommend-cate ']", 
                                        "//div[@class='cate-panel all-cate ']", 
                                        "//div[@class='cate-panel all-cate _NO_CLS_']",
                                        "//div[@class='cate-panel all-cate  whole-line']", 
                                        "//div[@class='cate-panel hierarchy-cate']",
                                        "//div[@class='cate-panel recommend-cate _NO_CLS_']"};

            foreach (String s in cates)
            {
                HAP.HtmlNode n = doc.DocumentNode.SelectSingleNode(s);
                List<Hashtable> cats1 = process_dldd(s, n);
                //要處理一下url.
                result.AddRange(cats1);
                cats1.Clear();
            }
            //1.先處理中間階段的
            int sz = crumbs.Count;
            for (int i = 1; i < sz; i++)
            {
                Hashtable htt = crumbs[i];
                String name = (String)htt["text"];
                String cat = (String)htt["cat"];
                tryCreateCategory(name, cat);
            }

            //試著建立所有cates
            foreach (Hashtable cat in result)
            {
                tryCreateCategory((String)cat["text"], (String)cat["cat"]);
            }

            // 如果有目前的cat 那就要處理階層關係
            //1.處理目前的 currentCat
            if (hasURLCat)
            {
                Hashtable ht = crumbs.Last();
                ht["cat"] = urlCat;
                //先更新這個level
                Guid id = tryCreateCategory((String)ht["text"], (String)ht["cat"]);

                //處理 crumb 跟 本類的關係
                if (crumbs.Count > 2)
                {
                    Hashtable pcrumbs = crumbs[crumbs.Count - 2];
                    tryAddCatRelation((String)pcrumbs["cat"], urlCat);
                }

                //'當q="" 時才處理leaf            
                if (String.IsNullOrWhiteSpace(q) && (cates.Count() == 0))
                {
                    setAsLeaf(urlCat);
                    //更新為 leaf
                }
                foreach (Hashtable cat in result)
                {
                    tryAddCatRelation(urlCat, (String)cat["cat"]);
                }
            }

            //最後處理 url
            foreach (Hashtable cat in result)
            {
                String h = (String)cat["href"];
                if (h.StartsWith("/"))
                {
                    cat["href"] = urlprefix + h;
                }
            }
            return result;
        }

        protected  static List<Hashtable> process_dldd(String cattype,HAP.HtmlNode parent)
        {
            List<Hashtable> result = new List<System.Collections.Hashtable>();
            if (parent == null)
                return result;
            HAP.HtmlNodeCollection nodes = parent.SelectNodes(parent.XPath + "/dl/dd/a");
            if (nodes != null)
            {
                foreach (HAP.HtmlNode node in nodes)
                {
                    String href = node.GetAttributeValue("href", "");
                    if (String.IsNullOrWhiteSpace(href))
                        continue;
                    href = href.Replace("&amp;", "&");
                    String title = node.GetAttributeValue("title", "");
                    Hashtable ht = HTMLHelpers.parseParameter(href);
                    ht.Add("text", title);
                    ht.Add("href", href);
                    result.Add(ht);
                }
            };
            return result;
        }

        protected static List<Hashtable> processCrumb(HAP.HtmlDocument doc)
        {
            List<Hashtable> result = new List<System.Collections.Hashtable>();
            HAP.HtmlNode crumbs = doc.DocumentNode.SelectSingleNode("//ul[@class='crumbs']");
            if (crumbs == null)
            {
                return result;
            }

            HAP.HtmlNodeCollection crumblist = crumbs.SelectNodes(crumbs.XPath + "/li[@class='list-item']");
            foreach (HAP.HtmlNode node in crumblist)
            {
                Hashtable ht = new System.Collections.Hashtable();
                result.Add(ht);
                HAP.HtmlNode a = node.SelectSingleNode(node.XPath + "/a");
                if (a != null)
                {
                    String href = a.GetAttributeValue("href", "");
                    if (String.IsNullOrWhiteSpace(href) == false)
                    {
                        ht["href"] = href;
                        Hashtable htt = HTMLHelpers.parseParameter(href);
                        String cat = (String)htt["cat"];
                        if (String.IsNullOrWhiteSpace(cat) == false)
                        {
                            ht["cat"] = cat;
                        }
                    }
                    ht["text"] = a.InnerText;
                }
                else
                {
                    ht["text"] = node.InnerText;
                }
            }
            return result;
        }


        protected static void updateCategory(String name, String code, bool isLeaf)
        {
            MyTaobao1DataContext context = LinqAgent.getTaobaoContext();
            if (String.IsNullOrWhiteSpace(code))
                return;
            TaobaoPick.Category ct = (from cat in context.Categories where cat.categoryName.Equals(name) select cat).FirstOrDefault();
            if (ct == null)
            {
                ct = new Category();
                ct.categoryName = name;
                ct.categoryCode = code;
                ct.categoryId = NewGUID.create("cate");
                ct.categoryLevel = 5;
                ct.isLeaf = isLeaf;
                ct.seq = name.Length;
                context.Categories.InsertOnSubmit(ct);
                context.SubmitChanges();
            }
            else
            {
                if (String.IsNullOrWhiteSpace(code) == false)
                    if (code.Equals(ct.categoryCode) == false)
                    {
                        ct.categoryCode = code;
                    }
                if (ct.isLeaf != isLeaf)
                {
                    ct.isLeaf = isLeaf;
                }
                context.SubmitChanges();
            }


        }


        // process CAT的功用在於處理CAT的架構, 並且取得有哪些CAT
        // 為了避免CAT repeat ,應該要記起來

        protected static Guid CreateCategory_sure(String categoryName, String catCode)
        {
            MyTaobao1DataContext context = LinqAgent.getTaobaoContext();
            Category c = new Category();
            c.categoryId = NewGUID.create("cate");
            c.categoryName = categoryName;
            c.categoryCode = catCode;
            c.seq = categoryName.Length;
            context.Categories.InsertOnSubmit(c);
            context.SubmitChanges();
            //放到cache
            codeToGuid[catCode] = c.categoryId;
            return c.categoryId;
        }
        //其實create category 主要還是要以code為主,因為name是附屬的

        public static Guid tryCreateCategory(String categoryName, String catCode)
        {
            //找到 categoryName ?
            MyTaobao1DataContext context = LinqAgent.getTaobaoContext();
            Category  c = (from cat in context.Categories where cat.categoryCode == catCode select cat).FirstOrDefault();
            if (c != null)
            {
                return c.categoryId;
            }

            List<Category> ccs= (from cat in context.Categories where cat.categoryName == categoryName select cat).ToList<Category>();
            if (ccs.Count == 0)
            {
                return CreateCategory_sure(categoryName, catCode);
            }
            else
             if(ccs.Count==1)
            {
                Guid result = Guid.Empty;
                foreach (Category ct in ccs)
                {
                    ct.categoryCode = catCode;
                    result = ct.categoryId;
                }
                context.SubmitChanges();
                return result;
            }
            throw new Exception("Category Name 多對1"+categoryName);
        }
        /// <summary>
        ///  透過 code取得 guid
        /// </summary>
        /// <param name="catCode"></param>
        /// <returns></returns>
        protected static Hashtable codeToGuid = new Hashtable();
        protected static Guid getCategoryId(String catCode)
        {
            if (codeToGuid.ContainsKey(catCode))
                return (Guid)codeToGuid[catCode];
            MyTaobao1DataContext context = LinqAgent.getTaobaoContext();
            Category c = (from cat in context.Categories where cat.categoryCode == catCode select cat).FirstOrDefault();
            if (c != null)
            {
                codeToGuid[catCode] = c.categoryId;
                return c.categoryId;
            }
            codeToGuid[catCode] = Guid.Empty;
            return Guid.Empty;
        }
        protected  static void tryAddCatRelation(String parentCat, String childCat)
        {
            Guid parentId = getCategoryId(parentCat);
            tryAddCatRelation(parentId, childCat);
        }
        /// <summary>
        /// 增加parent child 關係
        /// </summary>
        /// <param name="parentGuid"></param>
        /// <param name="catCode"></param>
        protected static void tryAddCatRelation(Guid parentGuid, String catCode)
        {
            if (Guid.Empty.Equals(parentGuid))
                throw new Exception("tryAddCatRelation  with Empty parameter : catCode=" + catCode);
            MyTaobao1DataContext context = LinqAgent.getTaobaoContext();
            Category c = (from cat in context.Categories where cat.categoryCode == catCode select cat).FirstOrDefault();
            if (parentGuid.Equals(c.parentCategory))
                return;
            c.parentCategory = parentGuid;
            context.SubmitChanges();
        }


        protected static void setAsLeaf(String catCode)
        {
            MyTaobao1DataContext context = LinqAgent.getTaobaoContext();
            Category c = (from cat in context.Categories where cat.categoryCode == catCode select cat).FirstOrDefault();
            if (c == null)
            {
                throw new Exception("setAsLeaf  with not created category : childCat=" + catCode);
            }
            if (c.isLeaf == true)
            {
                return;
            }
            c.isLeaf = true;
            context.SubmitChanges();
        }        
  

    }
}
